package base.thread_demo.demo08_03;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 终止模式之两阶段终止模式：在一个线程t1中如何优雅的终止线程t2，优雅是说给t2一个料理后事的机会。(本例中没有料理后事机会)
 * 模拟监控工具记录应用日志。
 * 提供手动关闭工具记录日志功能。
 * Thread.sleep()过程中被 Thread..interrupt()打断
 *
 * System.exit(int)，这种方式会让整个程序都停止.方法终止当前正在运行的 Java 虚拟机，参数解释为状态码。
 * 根据惯例，非 0 的状态码表示异常终止。 而且，该方法永远不会正常返回。 这是唯一一个能够退出程序并不执行finally的情况。
 */
public class InterruptMonitorTool {

    public static void main(String[] args) throws InterruptedException {
        MonitorTools tools = new InterruptMonitorTool().new MonitorTools();

        // 开启日志监控
        tools.start();

        // 模拟日常监控中
        Thread.sleep(10000);

        // 模拟手动关闭日志监控
        tools.stop();
    }


    /**
     * 监控工具封装类: 该案例不好的地方在于,需要时刻关注InterruptedException,根据是否异常来设置打断标志
     */
    class MonitorTools {
        private final Logger log = LoggerFactory.getLogger(MonitorTools.class);
        private Thread monitor;

        // 启动监控线程
        public void start() {
            monitor = new Thread(() -> {
                Thread currentThread = Thread.currentThread();
                while (!currentThread.isInterrupted()) {
                    try {
                        Thread.sleep(2000);//1、日志监控间隔2s监控一次，这里可能被打断
                        // 这里调用日志采集业务
                        log.info("功能：日志采集....");// 2、记录日志时，手动关闭监控线程开关
                    } catch (InterruptedException e) {
                        log.info("功能：结束收尾工作...");
                        // 线程在sleep、wait、join过程被打断，通过isInterrupted() API 发现打断标识被重置为false
                        // 所以这里再次调用interrupt()来将线程中断标识设为true，确保再次循环判断时不再进入循环,
                        // 从而达到手动关闭日志记录功能
                        currentThread.interrupt();// 打断标识设为true
                    }
                }
            });
            monitor.start();
        }

        // 停止监控线程
        public void stop() {
            log.info("关闭日志采集功能......");
            monitor.interrupt();
        }
    }

}
